package cn.izeno.wx.service

import cn.izeno.wx.Cache
import cn.izeno.wx.models.mp.SyncKeyRes
import cn.izeno.wx.models.web.Member
import cn.izeno.wx.web.ContactManager
import cn.izeno.wx.web.MessageReceiver
import io.reactivex.rxjava3.schedulers.Schedulers
import java.util.logging.Logger
import kotlin.random.Random

/**
 * ```
 *         +--------------+     +---------------+   +---------------+
 *         |              |     |               |   |               |
 *         |   Get UUID   |     |  Get Contact  |   | Status Notify |
 *         |              |     |               |   |               |
 *         +-------+------+     +-------^-------+   +-------^-------+
 *                 |                    |                   |
 *                 |                    +-------+  +--------+
 *                 |                            |  |
 *         +-------v------+               +-----+--+------+      +--------------+
 *         |              |               |               |      |              |
 *         |  Get QRCode  |               |  Weixin Init  +------>  Sync Check  <----+
 *         |              |               |               |      |              |    |
 *         +-------+------+               +-------^-------+      +-------+------+    |
 *                 |                              |                      |           |
 *                 |                              |                      +-----------+
 *                 |                              |                      |
 *         +-------v------+               +-------+--------+     +-------v-------+
 *         |              | Confirm Login |                |     |               |
 *  +------>    Login     +---------------> New Login Page |     |  Weixin Sync  |
 *  |      |              |               |                |     |               |
 *  |      +------+-------+               +----------------+     +---------------+
 *  |             |
 *  |QRCode Scaned|
 *  +-------------+
 *  ```
 *
 *  @see [微信网页版协议分析和实现机器人](https://juejin.im/entry/56ca789899a6ce005a07d4bd)

 */
object WebWxApp {
  var active = false

  var status: String = ""

  @Volatile
  var running = false

  lateinit var user: Member
  private val logger = Logger.getLogger(this::class.java.name)

  /**
   * 二级域名
   */
  var sld: String = "wx"
  var sid: String = ""
  var skey: String = ""
  var uin: String = ""
  var deviceId: String = "e" + Random.nextLong().toString().substring(1, 15)

  @Volatile
  var syncKey = SyncKeyRes()
  var passTicket: String = ""

  init {
    loadFromCache()
  }

  /**
   * 1. 获取 uuid
   * 2. 获取二维码
   * 3. 扫码登录
   * 4. 初始化
   * 5. 开启通知
   * 6. 开始接收消息
   */
  private fun login() {
    logger.warning("start login")
    Web.clearCookie()

    Web.uuid().flatMap { uuid ->
      val qrcodeUrl = "https://login.weixin.qq.com/qrcode/$uuid"
      logger.info("二维码链接:$qrcodeUrl")
      openUrl(qrcodeUrl)
      status = "请扫码登录<br/><img src='$qrcodeUrl'>"
//      Web.service.getQrcode(uuid).subscribe()
      Web.login(uuid)
    }.flatMap {
      // 记录二级域名
      sld = Regex("https://([^.]+).qq.com").find(it)?.groups?.get(1)?.value ?: "wx"
      Web.service.redirect(it)
    }.flatMap { info ->
      if (info.ret == 1203) {
        running = false
        status = "账号被限制登录微信网页版"
        throw RuntimeException("账号被限制登录微信网页版")
      }

      passTicket = info.passTicket
      sid = info.wxsid
      uin = info.wxuin
      skey = info.skey

      Web.service.init()
    }.subscribeOn(Schedulers.io()).subscribe({ initRes ->
      status = "登录成功， 用户: ${initRes.user.nickname}"
      active = true
      user = initRes.user
      syncKey = initRes.syncKey

      saveToCache()

      Web.service.statusNotify().subscribe()

      ContactManager.sync()
      // 同步联系人中的群信息
      ContactManager.syncChatRoom(*initRes.contactList.filter { it.username.startsWith("@@") }.map { it.username }.toTypedArray())
      MessageReceiver.start()

      running = true
    }, {
      running = false
      it.printStackTrace()
    })
  }

  private fun resume() {
    logger.warning("start resume")
    Web.service.init(ticket = "").subscribe({

      if (it.base.ret != 0) {
        throw IllegalStateException("登录失效")
      }

      status = "登录成功， 用户: ${it.user.nickname}"
      user = it.user
      syncKey = it.syncKey

      saveToCache()

      Web.service.statusNotify().subscribe()
      ContactManager.sync()
      // 同步联系人中的群信息
      ContactManager.syncChatRoom(*it.contactList.filter { it.username.startsWith("@@") }.map { it.username }.toTypedArray())
      MessageReceiver.start()

      running = true
    }, {
      it.printStackTrace()
      login()
    })
  }

  // 开始运行
  fun run() {
    if (running) return

    if (active) {
      this.resume()
    } else {
      this.login()
    }
  }

  fun exit(code: Int) {
    status = "登录信息失效"
    active = false
    running = false
  }


  private fun loadFromCache() {
    active = Cache["web_wx_app:active"] as? Boolean ?: active
    sld = Cache["web_wx_app:sld"] as? String ?: sld
    sid = Cache["web_wx_app:sid"] as? String ?: sid
    skey = Cache["web_wx_app:skey"] as? String ?: skey
    uin = Cache["web_wx_app:uin"] as? String ?: uin
    deviceId = Cache["web_wx_app:device_id"] as? String ?: deviceId
    syncKey = Cache["web_wx_app:sync_key"] as? SyncKeyRes ?: syncKey
  }

  private fun saveToCache() {
    Cache["web_wx_app:active"] = active
    Cache["web_wx_app:sld"] = sld
    Cache["web_wx_app:sid"] = sid
    Cache["web_wx_app:skey"] = skey
    Cache["web_wx_app:uin"] = uin
    Cache["web_wx_app:device_id"] = deviceId
    saveToSyncKeyCache()
  }


  private fun saveToSyncKeyCache() {
    Cache["web_wx_app:sync_key"] = syncKey
  }

  // 使用浏览器打开二维码
  private fun openUrl(url: String) {
    try {
      val uri = java.net.URI.create(url)
      //获取当前系统桌面扩展
      val dp = java.awt.Desktop.getDesktop()
      //判断系统桌面是否支持要执行的功能
      if (dp.isSupported(java.awt.Desktop.Action.BROWSE)) {
        //获取系统默认浏览器打开链接
        dp.browse(uri)
      }
    } catch (ignore: Exception) {
      logger.warning("系统没有可以打开图片链接的应用")
    }
  }
}
